package com.wyix.service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 多线程并发下载器，支持文件分块并行下载
 *
 * @author wangdx
 * @since 2025/8/1
 */
public class MultiThreadDownloader {
    private static final int THREAD_COUNT = 4; // 下载线程数
    private static final String TEMP_SUFFIX = ".part"; // 临时文件后缀
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";

    /**
     * 下载入口方法
     *
     * @param url      下载链接
     * @param filePath 保存路径（如 D:/test.zip）
     */
    public void download(String url, String filePath) throws InterruptedException {
        try {
            long fileSize = getFileSize(url); // 获取文件总大小
            System.out.println("文件总大小：" + fileSize + "字节，启动" + THREAD_COUNT + "个线程下载...");

            long blockSize = fileSize / THREAD_COUNT;
            CountDownLatch latch = new CountDownLatch(THREAD_COUNT); // 用于等待所有线程完成
            List<String> tempFiles = new ArrayList<>(); // 临时文件列表

            for (int i = 0; i < THREAD_COUNT; i++) {
                long start = i * blockSize;
                long end = (i == THREAD_COUNT - 1) ? fileSize - 1 : (i + 1) * blockSize - 1;
                String tempFile = filePath + TEMP_SUFFIX + i; // 临时文件路径（如 D:/test.zip.part0）
                tempFiles.add(tempFile);

                // 启动下载线程
                new Thread(() -> {
                    try {
                        downloadBlock(url, tempFile, start, end);
                        System.out.println("线程" + Thread.currentThread().getName() + "下载完成（" + start + "-" + end + "）");
                    } catch (IOException e) {
                        System.err.println("线程" + Thread.currentThread().getName() + "下载失败：" + e.getMessage());
                    } finally {
                        latch.countDown(); // 线程完成，计数器减1
                    }
                }, "下载线程-" + i).start();
            }

            latch.await(); // 等待所有线程下载完成
            mergeBlocks(filePath, tempFiles); // 合并临时文件
            System.out.println("文件下载完成：" + filePath);

        } catch (IOException e) {
            throw new RuntimeException("下载失败：" + e.getMessage());
        }
    }
    /**
     * 设置通用请求头
     */
    private void setCommonRequestHeaders(HttpURLConnection conn) {
        conn.setRequestProperty("User-Agent", USER_AGENT);
        conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
        conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
        conn.setRequestProperty("Connection", "keep-alive");
    }


    /**
     * 获取远程文件大小
     */
    private long getFileSize(String url) throws IOException {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("HEAD"); // 只请求头部信息
        // 设置 User-Agent 请求头
        conn.setRequestProperty("User-Agent", USER_AGENT);
        // 设置更多请求头
        setCommonRequestHeaders(conn);
        return conn.getContentLengthLong();
    }

    /**
     * 下载文件块（核心方法）
     */
    private void downloadBlock(String url, String tempFile, long start, long end) throws IOException {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        // 设置 User-Agent 请求头
        conn.setRequestProperty("User-Agent", USER_AGENT);
        conn.setRequestProperty("Range", "bytes=" + start + "-" + end); // 请求指定字节范围
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(10000);
        // 设置更多请求头
        setCommonRequestHeaders(conn);
        try (InputStream in = conn.getInputStream();
             RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) {

            raf.seek(0); // 从临时文件开头写入（因start是块起始位置，文件内偏移为0）
            byte[] buffer = new byte[4096];
            int len;
            while ((len = in.read(buffer)) != -1) {
                raf.write(buffer, 0, len);
            }
        }
    }

    /**
     * 合并临时文件块
     */
    private void mergeBlocks(String targetPath, List<String> tempFiles) throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(targetPath, "rw")) {
            for (String tempFile : tempFiles) {
                try (FileInputStream fis = new FileInputStream(tempFile)) {
                    byte[] buffer = new byte[4096];
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        raf.write(buffer, 0, len);
                    }
                }
                // 删除临时文件
                new File(tempFile).delete();
            }
        }
    }

    // 测试方法（需替换为真实下载链接）
    public static void main(String[] args) throws InterruptedException {
        MultiThreadDownloader downloader = new MultiThreadDownloader();
        downloader.download(
                "https://mirrors.tuna.tsinghua.edu.cn/debian/dists/Debian12.11/main/Contents-mips64el.gz", // 替换为真实下载URL
                "D:/download/large-file.zip"          // 保存路径
        );
    }
}